const Vue = require('vue')
const express = require('express')
const fs = require('fs')
const {
  createBundleRenderer
} = require('vue-server-renderer')
const setupDevServer = require('./build/setup-dev-server')
const server = express()


/**
 * 第一个参数是请求的路径
 * 第二个参数是查找资源的路径
 */
server.use('/dist', express.static('./dist'))

const isProd = process.env.NODE_ENV === 'production'


let renderer
let onReady
if (isProd) {
  const serverBundle = require('./dist/vue-ssr-server-bundle.json')
  const template = fs.readFileSync('./index.template.html', 'utf-8')
  // 构建打包资源的清单
  const clientManifest = require('./dist/vue-ssr-client-manifest.json')
  // 渲染器
  renderer = createBundleRenderer(serverBundle, {
    template,
    clientManifest
  })
} else {
  // 开发模式 -> 监视打包构建 -> 重新生成 Renderer 渲染器
  // 设置开发模式下的服务
  onReady = setupDevServer(server, (serverBundle, template, clientManifest) => {
    renderer = createBundleRenderer(serverBundle, {
      template,
      clientManifest
    })
  })
}



/**
 * render 作用是路由渲染
 * renderer 作用是 ssr 服务器渲染
 * @param {*} req 
 * @param {*} res 
 */
const render = async (req, res) => {
  try {
    // 渲染器
    // 在渲染的时候，会加载 serverbundle 并执行
    // 渲染后会加载到 template 模板文件，并输出到浏览器
    const html = await renderer.renderToString({
      title: '拉勾教育',
      meta: `<meta name="description" content="拉勾教育">`,
      url: req.url
    })
    // 增加响应头的编码，防止展示页面的时候乱码
    res.setHeader('Content-Type', 'text/html; charset=utf8')
    // 返回渲染后的 html
    res.end(html)
  } catch (error) {
    return res.status(500).end('Internal Server Error.')
  }
}


/**
 * 判断是否生产模式，如果是生产模式就直接调用 render 函数进行渲染
 * 如果是开发模式，就需要等待 renderer 渲染器重新打包构建以后才进行重新渲染
 * 服务端路由设置为 * ,意味着所有的路由都会进入这里
 */
server.get('*', isProd ? render : async (req, res) => {
  // 等待有了 Renderer 渲染器以后，再调用 render 进行渲染
  await onReady
  render(req, res)
})

server.listen(3000, () => {
  console.log('server running at port 3000')
})